/* storage

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"

#include "cJSON.h"

#include "storage.h"

static const char *TAG = "storage";

DeviceConfig_t DeviceConfig;


/**
  * @brief  None
  * @param  None
  * @retval None
  */
bool SPIFFS_InitAndmounted( void )
{
#if (USE_SPIFFS_ON == 0)
	return false;
#endif

	ESP_LOGI(TAG, "Initializing SPIFFS");
	 
	 esp_vfs_spiffs_conf_t conf = {
	   .base_path = "/spiffs",
	   .partition_label = NULL,
	   .max_files = 5,
	   .format_if_mount_failed = true
	 };
	 
	 // Use settings defined above to initialize and mount SPIFFS filesystem.
	 // Note: esp_vfs_spiffs_register is an all-in-one convenience function.
	 esp_err_t ret = esp_vfs_spiffs_register(&conf);
	
	 if (ret != ESP_OK) {
		 if (ret == ESP_FAIL) {
			 ESP_LOGE(TAG, "Failed to mount or format filesystem");
		 } else if (ret == ESP_ERR_NOT_FOUND) {
			 ESP_LOGE(TAG, "Failed to find SPIFFS partition");
		 } else {
			 ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
		 }
		 return false;
	 }
	 
	 size_t total = 0, used = 0;
	 ret = esp_spiffs_info(NULL, &total, &used);
	 if (ret != ESP_OK) {
		 ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
	 } else {
		 ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
	 }

	return true;
}

/**
  * @brief  None
  * @param  None
  * @retval None
  */
void SPIFFS_Unmounted( void )
{
#if (USE_SPIFFS_ON == 0)
	return false;
#endif

	 // All done, unmount partition and disable SPIFFS
	 esp_vfs_spiffs_unregister(NULL);
	 ESP_LOGI(TAG, "SPIFFS unmounted");
}

/**
  * @brief  None
  * @param  None
  * @retval None
  */
bool GetDeviceConfig(DeviceConfig_t *pDeviceConfig)
{
#if (USE_SPIFFS_ON == 0)
	return false;
#endif

	FILE* fd_file = NULL;

	struct stat st;	
	if( stat("/spiffs/device1.txt", &st) == 0 )
	{
		fd_file = fopen( "/spiffs/device1.txt", "r" );	//Open and create file
	}
	else if( stat("/spiffs/device2.txt", &st) == 0 )
	{
		fd_file = fopen( "/spiffs/device2.txt", "r" );	//Open and create file
	}
	else
	{
		fd_file = NULL;
	}

	if( fd_file != NULL )
	{	
		if( st.st_size < 1025 )
		{
			char deviceFileContent[1025];

			ssize_t readLen;

			readLen = fread(deviceFileContent, 1, 1024, fd_file );

			ESP_LOGI(TAG,"device.txt readLen:%d\r\n", readLen);
			
			if( readLen > 0 )
			{
				cJSON *pJsonRoot = cJSON_Parse( deviceFileContent );
				if( pJsonRoot!= NULL )
				{
					cJSON * pJsonObj = cJSON_GetObjectItem(pJsonRoot, "mqttDomain");
					if( pJsonObj != NULL )
					{
						if( cJSON_IsString(pJsonObj) )
						{
							strcpy( pDeviceConfig->mqttDomain, pJsonObj->valuestring );
						}
					}

					pJsonObj = cJSON_GetObjectItem(pJsonRoot, "mqttPort");
					if( pJsonObj != NULL )
					{
						if( cJSON_IsString(pJsonObj) )
						{
							pDeviceConfig->mqttPort = atoi(pJsonObj->valuestring);
						}
					}	

					pJsonObj = cJSON_GetObjectItem(pJsonRoot, "mqttUsername");
					if( pJsonObj != NULL )
					{
						if( cJSON_IsString(pJsonObj) )
						{
							strcpy( pDeviceConfig->mqttUsername, pJsonObj->valuestring );
						}
					}			

					pJsonObj = cJSON_GetObjectItem(pJsonRoot, "mqttPassword");
					if( pJsonObj != NULL )
					{
						if( cJSON_IsString(pJsonObj) )
						{
							strcpy( pDeviceConfig->mqttPassword, pJsonObj->valuestring );
						}
					}

					pJsonObj = cJSON_GetObjectItem(pJsonRoot, "loginPassword");
					if( pJsonObj != NULL )
					{
						if( cJSON_IsString(pJsonObj) )
						{
							strcpy( pDeviceConfig->loginPassword, pJsonObj->valuestring );
						}
					}				
				}
				
			}
		}
		
		fclose(fd_file);

		return true;
	}
	else
	{
		ESP_LOGI(TAG,"open device.txt fail!\r\n");
	}

	return false;
}
/**
  * @brief  None
  * @param  None
  * @retval None
  */
bool SetDeviceConfig(DeviceConfig_t *pDeviceConfig)
{
#if (USE_SPIFFS_ON == 0)
	return false;
#endif

	FILE* fd_file = NULL;

	char RemoveFileName[40] = {'\0'};

	struct stat st;	
	if( stat("/spiffs/device1.txt", &st) == 0 )			// Check if destination file exists
	{
		fd_file = fopen( "/spiffs/device2.txt", "w" );	//Open or create file
		if( fd_file == NULL )
		{
			return false;
		}
		strcpy(RemoveFileName, "/spiffs/device1.txt" );

		ESP_LOGI(TAG,"open device2.txt\n");
	}
	else
	{
		fd_file = fopen( "/spiffs/device1.txt", "w" );		//Open or create file
		ESP_LOGI(TAG,"open device1.txt\n");
	}

	if( fd_file == NULL )
	{
		return false;
	}
	
	if( fseek(fd_file, 0, SEEK_SET) != 0 )
	{
		fclose( fd_file );
		return false;
	}

	cJSON* cJson_post = cJSON_CreateObject();
	cJSON_AddStringToObject( cJson_post, "mqttDomain", pDeviceConfig->mqttDomain );

	char portStr[6];
	sprintf( portStr, "%d", pDeviceConfig->mqttPort);
	cJSON_AddStringToObject( cJson_post, "mqttPort", portStr );
	cJSON_AddStringToObject( cJson_post, "mqttUsername", pDeviceConfig->mqttUsername );
	cJSON_AddStringToObject( cJson_post, "mqttPassword", pDeviceConfig->mqttPassword );
	cJSON_AddStringToObject( cJson_post, "loginPassword", pDeviceConfig->loginPassword );
	
	char *json_data = cJSON_Print( cJson_post );
	cJSON_Delete(cJson_post);
	
	if( fprintf (fd_file, "%s", json_data ) == strlen(json_data) )
	{
		free(json_data);
		ESP_LOGI(TAG,"fprintf sucess\n");
		if( fclose( fd_file ) != 0 )
		{
			return false;
		}

		if( strlen(RemoveFileName) > 0 )
		{
			if( remove( RemoveFileName ) == -1 )
			{
				return false;
			}
		}
		
	}
	else
	{
		free(json_data);
		ESP_LOGI(TAG,"fprintf fail\n");
		return false;
	}

	return true;
}


